package jmine.tec.rtm.impl.web.pages;

import static jmine.tec.web.wicket.pages.form.WebFormPagesMessages.ERROR_CANNOT_FIND_ENTITY_TO_VIEW;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

import jmine.tec.report.api.RendererTarget;
import jmine.tec.report.impl.ReportBuilder;
import jmine.tec.report.impl.table.CellValueResolver;
import jmine.tec.report.impl.table.RendererParameterInterface;
import jmine.tec.report.impl.table.ReportTableBuilder;
import jmine.tec.report.pdf.ReportPDFExporter;
import jmine.tec.web.pages.HelpTextMessages;
import jmine.tec.web.wicket.component.InlinedLabel;
import jmine.tec.web.wicket.component.command.img.ImageCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommandHandler;
import jmine.tec.web.wicket.component.report.AbstractComponentValueResolver;
import jmine.tec.web.wicket.pages.form.ListPage;
import jmine.tec.web.wicket.pages.validator.DateIntervalFormValidator;

import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.validation.IFormValidator;
import org.apache.wicket.model.PropertyModel;

import bancosys.tec.exception.BusinessException;
import bancosys.tec.exception.MessageCreator;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.rtm.exception.RTMException;
import bancosys.tec.rtm.impl.exception.dao.ExceptionRecordDAO;
import bancosys.tec.rtm.impl.exception.domain.ExceptionRecord;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;
import bancosys.tec.utils.date.Date;

/**
 * Tela de consulta para exceções do RTM, encapsuladas na entidade {@link ExceptionRecord}.
 * 
 * @author finx
 * @created Oct 27, 2010
 */
@Secure(id = "URL_LIST_EXCEPTION_RECORD", permissionType = UrlPermission.class)
public class ConsultaExceptionRecord extends ListPage<ExceptionRecord, ExceptionRecord> implements ViewCommandHandler {

    private static final double W7D = 7D;

    private static final double W05D = 0.5D;

    // numero maximo de dias em uma consulta
    private static final int MAXDAYS = 7;

    private Integer fatoIdStart;

    private Integer fatoIdEnd;

    private final Date startDate = new Date();

    private final Date finalDate = new Date();

    private FormComponent<java.util.Date> startDateComponent;

    private FormComponent<java.util.Date> endDateComponent;
    
    private String horarioStart;

    private String horarioEnd;

    private String user;

    private String system;

    /**
     * Construtor.
     */
    public ConsultaExceptionRecord() {
        super();
    }

    /**
     * Construtor.
     * 
     * @param pageParameters {@link PageParameters}
     */
    public ConsultaExceptionRecord(PageParameters pageParameters) {
        super(pageParameters);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected ExceptionRecord createModel() {
        return this.daoFactoryRef.get().getGenericDAO(ExceptionRecord.class).createBean();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return HelpTextMessages.CONSULTA_EXCEPTION_RECORD;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean shouldIncludeTableCommands() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<ImageCommand> getTableCommands(ExceptionRecord entity) {
        List<ImageCommand> commands = new ArrayList<ImageCommand>();
        commands.add(new ViewCommand(this));
        return commands;
    }

    /**
     * {@inheritDoc}
     */
    public List<ExceptionRecord> search(BaseDAOFactory daoFactory) {
        if (this.hasErrorMessage()) {
            return Collections.emptyList();
        }
        
        long idStart = -1;
        long idEnd = -1;
        if (this.fatoIdStart != null) {
            idStart = this.fatoIdStart;
        }
        if (this.fatoIdEnd != null) {
            idEnd = this.fatoIdEnd;
        }
        Calendar startDateCal = Calendar.getInstance();
        startDateCal.setTime(this.startDate);
        Calendar finalDateCal = Calendar.getInstance();
        finalDateCal.setTime(this.finalDate);

        try {
            ExceptionRecordDAO dao = daoFactory.getDAOByClass(ExceptionRecordDAO.class);
            return dao.findTraces(idStart, idEnd, startDateCal, finalDateCal, this.horarioStart, this.horarioEnd, this.user, this.system);
        } catch (RTMException e) {
            return Collections.emptyList();
        }
    }


    /**
     * {@inheritDoc}
     */
    @Override
    protected List<IFormValidator> createFormValidators() {
        return Collections.<IFormValidator>singletonList(new DateIntervalFormValidator(startDateComponent, endDateComponent, MAXDAYS));
    }
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected void addSearchFields(WebMarkupContainer container) {       
        this.startDateComponent = this.createDateField("startDate", new PropertyModel<Date>(this, "startDate")).setRequired(true);
        this.endDateComponent = this.createDateField("finalDate", new PropertyModel<Date>(this, "finalDate")).setRequired(true);
        container.add(this.startDateComponent);
        container.add(this.endDateComponent);
        container.add(this.createTextField("fatoIdStart", new PropertyModel<Long>(this, "fatoIdStart")));
        container.add(this.createTextField("fatoIdEnd", new PropertyModel<Long>(this, "fatoIdEnd")));
        container.add(this.createTextField("horarioStart", new PropertyModel<String>(this, "horarioStart")));
        container.add(this.createTextField("horarioEnd", new PropertyModel<String>(this, "horarioEnd")));
        container.add(this.createTextField("user", new PropertyModel<String>(this, "user")));
        container.add(this.createTextField("system", new PropertyModel<String>(this, "system")));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addResultTableColumns(ReportTableBuilder<ExceptionRecord> table) {
        table.addTimestampColumn("hora", "Data/Hora", "timestamp");
        this.createRPI(table.addNumberColumn("id", "ID", "id", 0)).setRelativeWidth(W05D);
        this.createRPI(table.addStringColumn("user", "Usuário", "user")).setRelativeWidth(W05D);
        this.createRPI(table.addStringColumn("system", "Sistema", "system")).setRelativeWidth(W05D);
        this.createRPI(table.addStringColumn("mensagem", "Mensagem", new ExceptionRecordMessageValueResolver())).setRelativeWidth(W7D);

    }

    /**
     * Create a {@link RendererParameterInterface} for {@link RendererTarget}
     * 
     * @param target the {@link RendererTarget}
     * @return the {@link RendererParameterInterface}
     */
    private RendererParameterInterface createRPI(RendererTarget target) {
        return new RendererParameterInterface(target);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void addReportHeader(ReportBuilder reportBuilder) {
        super.addReportHeader(reportBuilder);
        reportBuilder.getReportParameter().put(ReportPDFExporter.PAISAGEM, "false");
        reportBuilder.addHeaderDateParameter("dataInicio", "Data Início", this.startDate);
        reportBuilder.addHeaderDateParameter("dataFim", "Data Fim", this.finalDate);
        if (this.user != null) {
            reportBuilder.addHeaderStringParameter("user", "Usuário", this.user);
        }
        if (this.system != null) {
            reportBuilder.addHeaderStringParameter("system", "System", this.system);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Page createViewPage(Serializable entityPk) {
        try {
            ExceptionRecord entity = this.loadEntity(entityPk);
            return new ConsultaDetalheExceptionRecord(this, entity);
        } catch (BeanNotFoundException e) {
            throw new BusinessException(ERROR_CANNOT_FIND_ENTITY_TO_VIEW.create(this.getPageName(), entityPk));
        }
    }

    /**
     * Por padrão resolve para a stack trace completa, no caso de tela cria um Inlined Label com apenas a mensagem
     * 
     * @author heitor.marcos
     */
    private class ExceptionRecordMessageValueResolver extends AbstractComponentValueResolver<ExceptionRecord> {

        /**
         * Constructor
         */
        public ExceptionRecordMessageValueResolver() {
            super(new CellValueResolver<ExceptionRecord>() {
                public Object resolveCellValue(ExceptionRecord rowValue) {
                    return rowValue.getStackFormatada();
                }
            });
        }

        /**
         * {@inheritDoc}
         */
        public Component createComponents(String componentId, ExceptionRecord value) {
            return new InlinedLabel(componentId, value.getMensagem());
        }
    }
}
